package org.wujiangbo.controller;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.wujiangbo.annotation.CheckPermission;
import org.wujiangbo.domain.user.User;
import org.wujiangbo.mapper.user.UserMapper;
import org.wujiangbo.result.JSONResult;
import org.wujiangbo.thread.InsertUserThread;
import org.wujiangbo.utils.FreemarkerExportWordUtil;
import org.wujiangbo.utils.RedisService;
import org.wujiangbo.utils.Tools;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @desc 测试接口类
 * @author 波波老师(weixin：javabobo0513)
 */
@RestController
@Slf4j
public class TestController {

    @Resource
    private RedisService redisService;

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    /**
     * IO密集型任务 = 一般为2*CPU核心数（常出现于线程中：数据库数据交互、文件上传下载、网络数据传输等等）
     * CPU密集型任务 = 一般为CPU核心数+1（常出现于线程中：复杂算法）
     * 混合型任务 = 根据机器配置和复杂度自测而定
     */
    //private static int corePoolSize = Runtime.getRuntime().availableProcessors();
    private static int corePoolSize = 6;

    //自定义线程池
    private static ThreadPoolExecutor executor = new ThreadPoolExecutor(
            corePoolSize, //指定核心线程数量
            2 * corePoolSize, //指定最大线程数
            10L, //指定线程空闲后的最大存活时间
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(), //任务较多时暂存到此队列（无界队列）
            new ThreadPoolExecutor.DiscardPolicy() //策略：丢弃任务
    );

    /**
     * 向数据库批量添加数据（线程池方式）
     */
    @GetMapping("/insertUser/{count}")
    public JSONResult insertUser(@PathVariable("count") Integer count){
        log.info("共需要添加{}条数据入库", count);
        int countNum = 10000;//每个线程往数据库新增数据的条数 10000
        log.info("每个线程往数据库新增{}条数据", countNum);
        int num = count / countNum;//循环次数
        log.info("循环{}次", num);
        //闭锁
        CountDownLatch latch = new CountDownLatch(num);
        long t1 = System.currentTimeMillis();
        for(int i=1; i<=num; i++){
            //获取测试用户集合数据
            List<User> userList = Tools.getUserList(countNum);

            //如果自动提交设置为true，将无法控制提交的条数。所以我这里设置为false，，改为统一提交
            SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
            UserMapper userMapper = session.getMapper(UserMapper.class);
            executor.execute(new InsertUserThread(userList, latch, userMapper, session));
        }
        try {
            latch.await();//等待所有线程执行完成之后，再统计执行时间
            long t2 = System.currentTimeMillis();
            log.info("---------------数据入库任务-执行完毕，总耗时：{}毫秒", (t2 - t1));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return JSONResult.success();
    }

    /**
     * 根据ftl模板模板下载word文档
     */
    @GetMapping("/downloadWord")
    public void downloadWord(HttpServletResponse response){
        Map<String, Object> map = new HashMap<>();
        map.put("username", "王天霸");//姓名
        map.put("idno", "429004199601521245");//身份证号
        map.put("hireDate", "2021年12月12日");//入职日期
        map.put("work", "Java软件工程师");//职务
        map.put("endDate", "2022年11月25日");//离职日期
        map.put("imageData", Tools.getBase64ByPath("D:\\demo\\test.png"));//盖章Base64数据（不包含头信息）
        try {
            FreemarkerExportWordUtil.exportWord(response, map, "离职证明.doc", "EmploymentSeparationCertificate.ftl");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //测试Redis存值取值
    @GetMapping("/testRedis")
    public JSONResult testRedis(){
        redisService.setCacheObject("test", "testRedis", 1, TimeUnit.MINUTES);
        return JSONResult.success(redisService.getCacheObject("test"));
    }

    //用户新增接口
    @GetMapping("/user/addUser")
    @CheckPermission(per = "user:addUser")
    public JSONResult addUser(){
        return JSONResult.success("addUser success");
    }

    //部门新增接口
    @GetMapping("/dept/addDept")
    @CheckPermission(per = "user:addDept")
    public JSONResult addDept(){
        return JSONResult.success("addDept success");
    }

    //测试接口
    @GetMapping("/getUser")
    public JSONResult getUser(){
        return JSONResult.success("getUser");
    }
}